﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
//using GwLib.Common;
//using GwLib.Utility;

namespace GwLib.JqGridMvc
{
    public class JqGridAjaxEventArgsModelBinder : IModelBinder
    {

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            ValueProviderResult _search = bindingContext.ValueProvider.GetValue("_search");
            ValueProviderResult nd = bindingContext.ValueProvider.GetValue("nd");
            ValueProviderResult rows = bindingContext.ValueProvider.GetValue("rows");
            ValueProviderResult page = bindingContext.ValueProvider.GetValue("page");
            ValueProviderResult sidx = bindingContext.ValueProvider.GetValue("sidx");
            ValueProviderResult sord = bindingContext.ValueProvider.GetValue("sord");
            ValueProviderResult searchField = bindingContext.ValueProvider.GetValue("searchField");
            ValueProviderResult searchString = bindingContext.ValueProvider.GetValue("searchString");
            ValueProviderResult searchOper = bindingContext.ValueProvider.GetValue("searchOper");
            ValueProviderResult filters = bindingContext.ValueProvider.GetValue("filters");

            JqGridAjaxEventArgs args = new JqGridAjaxEventArgs();
            if (_search != null && !string.IsNullOrWhiteSpace(_search.AttemptedValue)) args.IsSearchRequest = (bool)_search.ConvertTo(typeof(bool));
            if (rows != null && !string.IsNullOrWhiteSpace(rows.AttemptedValue)) args.RecordsPerPage = (int)rows.ConvertTo(typeof(int));
            if (page != null && !string.IsNullOrWhiteSpace(page.AttemptedValue)) args.PageNumber = (int)page.ConvertTo(typeof(int));
            if (searchField != null && !string.IsNullOrWhiteSpace(searchField.AttemptedValue)) args.SearchField = searchField.AttemptedValue;
            if (searchString != null && !string.IsNullOrWhiteSpace(searchString.AttemptedValue)) args.SearchString = searchString.AttemptedValue;
            if (filters != null && !string.IsNullOrWhiteSpace(filters.AttemptedValue)) args.FilterString = filters.AttemptedValue;
            if (sidx != null && !string.IsNullOrWhiteSpace(sidx.AttemptedValue)) args.SortField = sidx.AttemptedValue;
            
            if (sord != null && !string.IsNullOrWhiteSpace(sord.AttemptedValue))
                args.SortAscending = sord.AttemptedValue == "asc";
            else
                args.SortAscending = true;

            if (nd != null && !string.IsNullOrWhiteSpace(nd.AttemptedValue))
            {
                DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
                args.RequestTime = origin.AddMilliseconds((long)nd.ConvertTo(typeof(long))).ToLocalTime();
            }

            if (!string.IsNullOrWhiteSpace(args.FilterString))
            {
                args.Filters = new List<IGridSearchFilter>();
                JsonFilter filter = SerializationUtility.DeserializeFromJson<JsonFilter>(args.FilterString);
                List<JsonFilter> fs = new List<JsonFilter>();
                PopulateFilterList(filter, fs);

                foreach (var f in fs) 
                {
                    var fg = new JqGridAjaxSearchFilter
                        {
                            GroupOperator = GetGroupOperatorFromString(f.groupOp),
                            SearchEntries = new List<IGridSearchFilterEntry>()
                        };
                    if (f.rules != null && f.rules.Length > 0)
                    {
                        foreach (var rule in f.rules)
                        {
                            fg.SearchEntries.Add(new JqGridAjaxSearchFilterEntry
                            {
                                SearchField = rule.field,
                                SearchOperator = GetSearchOperatorFromString(rule.op),
                                SearchString = rule.data
                            });
                        }
                        args.Filters.Add(fg);
                    }
                }

            }
            
            if (searchOper != null && !string.IsNullOrWhiteSpace(searchOper.AttemptedValue)) 
            {
                string op = searchOper.AttemptedValue;
                args.SearchOperator = GetSearchOperatorFromString(searchOper.AttemptedValue);
            }

            args.Filters = args.Filters ?? new List<IGridSearchFilter>();
            return args;
        }

        protected void PopulateFilterList(JsonFilter sourceFilter, List<JsonFilter> filters)
        {
            filters.Add(sourceFilter);
            if (sourceFilter.groups != null && sourceFilter.groups.Length > 0)
            {
                foreach (var childFilter in sourceFilter.groups)
                {
                    PopulateFilterList(childFilter, filters);
                }
            }
        }

        protected GroupOperator GetGroupOperatorFromString(string op)
        {
            GroupOperator groupOperator = GroupOperator.And;
            switch (op)
            {
                case "AND": groupOperator = GroupOperator.And; break;
                case "OR": groupOperator = GroupOperator.Or; break;
            }
            return groupOperator;
        }

        protected SearchOperator GetSearchOperatorFromString(string op)
        {
            SearchOperator searchOperator = SearchOperator.Contains;
            switch (op)
            {
                case "eq": searchOperator = SearchOperator.Equal; break;
                case "ne": searchOperator = SearchOperator.NotEqual; break;
                case "lt": searchOperator = SearchOperator.Less; break;
                case "le": searchOperator = SearchOperator.LessOrEqual; break;
                case "gt": searchOperator = SearchOperator.Greater; break;
                case "ge": searchOperator = SearchOperator.GreaterOrEqual; break;
                case "bw": searchOperator = SearchOperator.BeginsWith; break;
                case "bn": searchOperator = SearchOperator.DoesNotBeginWith; break;
                case "in": searchOperator = SearchOperator.IsIn; break;
                case "ni": searchOperator = SearchOperator.IsNotIn; break;
                case "ew": searchOperator = SearchOperator.EndsWith; break;
                case "en": searchOperator = SearchOperator.DoesNotEndWith; break;
                case "cn": searchOperator = SearchOperator.Contains; break;
                case "nc": searchOperator = SearchOperator.DoesNotContain; break;
            }
            return searchOperator;
        }

        //{"groupOp":"AND","rules":[{"field":"a.id","op":"eq","data":"12"},{"field":"a.total","op":"eq","data":"840"},{"field":"a.id","op":"eq","data":""}],"groups":[{"groupOp":"AND","rules":[{"field":"a.invdate","op":"nn","data":""}],"groups":[]}]}

        protected class JsonFilter
        {
            public string groupOp { get; set; }
            public Rule[] rules { get; set; }
            public JsonFilter[] groups { get; set; }
        }
        protected class Rule
        {
            public string field { get; set; }
            public string op { get; set; }
            public string data { get; set; }
        }
    }
}
